package com.tiantian.novel.helper;

import org.jsoup.Connection;
import org.jsoup.HttpStatusException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.*;
import java.io.IOException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Map;

/**
 * Http utils
 *
 * @author wangkai
 * @since 2020/12/18.
 */
public class HttpHelper {
    private static final Logger log = LoggerFactory.getLogger(HttpHelper.class);
    private static final String USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.87 Safari/537.36 SE 2.X MetaSr 1.0";
    private String userAgent;
    private boolean https;
    private boolean initedHttp;

    public HttpHelper(String userAgent, boolean https) {
        this.userAgent = userAgent;
        this.https = https;
        _initHttps();
    }

    public HttpHelper() {
        this(USER_AGENT, false);
    }

    public HttpHelper(boolean https) {
        this(USER_AGENT, https);
    }

    private void _initHttps() {
        if (!https) {
            return;
        }
        if (initedHttp) {
            return;
        }
        try {
            // 重置HttpsURLConnection的DefaultHostnameVerifier，使其对任意站点进行验证时都返回true
            HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            });
            // 创建随机证书生成工厂
            SSLContext context = SSLContext.getInstance("TLSv1.2");
            context.init(null, new X509TrustManager[]{new X509TrustManager() {
                @Override
                public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                }

                @Override
                public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                }

                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return new X509Certificate[0];
                }
            }}, new SecureRandom());

            // 重置httpsURLConnection的DefaultSSLSocketFactory， 使其生成随机证书
            HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
        } catch (Exception e) {
            e.printStackTrace();
        }
        initedHttp = true;
    }

    /**
     * Send http by Get
     *
     * @param url
     *
     * @return
     */
    public String getHtml(String url) throws IOException {
        return getBody(url).html();
    }

    /**
     * Get html
     *
     * @param url
     */
    public Element getBody(String url) throws IOException {
        _initHttps();
        log.info("Get Html from 【{}】", url);
        try {
            Document document = Jsoup.connect(url)
                    .ignoreContentType(true)
                    .userAgent(userAgent)
                    .timeout(30000).get();
            return document.body();
        } catch (HttpStatusException e) {
            log.info("JSOUP errror:{}", e.toString());
            return null;
        } catch (SSLHandshakeException e) {
            log.error("", e);
            // https://zhengqing.blog.csdn.net/article/details/109426192
            // 服务端的协议错误导致https不能正常访问，因此只能尝试访问http
            // return getBody(url.replace("https:", "http:"));
            return null;
        }
    }

    /**
     * Get Image
     *
     * @param url
     *
     * @return
     */
    public byte[] getImage(String url) throws IOException {
        _initHttps();
        Connection.Response response = Jsoup.connect(url)
                .ignoreContentType(true)
                .userAgent(userAgent)
                .timeout(30000).execute();
        return response.bodyAsBytes();
    }

    /**
     * json请求
     *
     * @param url
     * @param cookies
     *
     * @return
     */
    public String getJson(String url, Map<String, String> cookies) throws IOException {
        _initHttps();
        log.info("Get JSON from 【{}】", url);
        Connection conn = Jsoup.connect(url)
                .ignoreContentType(true)
                .ignoreHttpErrors(true)
                .userAgent(userAgent)
                .timeout(30000);
        if (cookies != null) {
            conn.cookies(cookies);
        }

        Connection.Response res = conn.execute();
        return res.body();
    }
}
